package com.itheima.demo1;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/*
    无论是我不创建对象或者创建对象，我老是以为每一个囚犯的编号，就是定义的数组或者list的索引号，
        所以下意识的想：数组或者list，或者list转为set后，删除奇数位置元素，索引变了，那编号怎么记录。想歪了
 */
public class Test1 {
    // 目标：完成幸存者案例。
    // 1、由于每个囚犯是一个对象，并且我们需要每个囚犯的编号和位置，所以我们把囚犯定义成对象来实现这个案例会更好。
    // 2、创建100个囚犯，依次占位，并为期赋值编号（1-200之间的随机数，不能重复）
    public static List<People> peoples = new ArrayList<>();     //用多态写
    public static void main(String[] args) {

        //isCanUse的形参需要接list集合，很不方便，所以把list集合定义为final static类型，方便调用
        //List<People> peoples = new ArrayList<>();

        // 3、循环100次，创建100个囚犯，存入集合
        Random r = new Random();
        //注意要求：然后让他们依次站成一排。(注：位置是从1开始计数的，所以位置记录是从1开始的
        for (int i = 1; i <= 100; i++) {
            //放在死循环中，只有添加了不重复编号的元素才能进入for的下一个循环。
            while (true) {
                int code = r.nextInt(200) + 1;
                //随机生成的编号，也有可能与list集合里面元素的编号重复，判断这个编号是否是唯一的。
                //独立功能，设置为独立方法，并且该方法还需要接集合进去
                if (isCanUse(code)) {
                    People p = new People(code, i);
                    peoples.add(p);
                    break; // 代表当前囚犯添加成功！
                }
            }
        }
/*
        for (int i = 1; i <= 100; i++) {
                int code = r.nextInt(200) + 1;
                //随机生成的编号，也有可能与list集合里面元素的编号重复，判断这个编号是否是唯一的。
                //独立功能，设置为独立方法，并且该方法还需要接集合进去
                if (isCanUse(code)) {
                    People p = new People(code, i);
                    peoples.add(p);
                }else {
                    i--;            //或者不用while死循环，如果判断编号重复就i--，i回退，重新来一轮for循环
                }
        }
        */

        System.out.println("囚犯占位：" + peoples);

        //用变量记录第几次死循环得到最终结果：
        int a = 0;

        //每一轮都要干掉奇数位置(索引为奇数位置)处的人:那不就是留下偶数位置处的人吗？神来之笔：逆向思维，去除奇数位==留下偶数位
        // 4、反复删除奇数位置处的人，直到剩余一个人为止。因为位置是1开始记录的，所以p1元素的位置是1，也就是要去除的奇数位
        // peoples = [p1, p2, p3 , p4, p5, p6.... ]     要留下位置是偶数的元素==也就是说留下奇数位索引的元素
        //            0   1   2    3    4   5
        //也可以独立写成一个方法来做，只要list列表里的数据多于一个，就需要删除，这样很明显用死循环
        while (peoples.size() > 1) {
            a++;
            List<People> tempPeoples = new ArrayList<>();
            //要留下位置是偶数的元素==也就是说留下奇数位索引的元素,所以从1开始遍历数据
            //并且有一点容易弄乱，每一轮循环删减之后，又会有新的索引为奇数的元素需要删除，
            // 但是磊哥用对象的思想把每一个元素的初始位置给记录了下来
            for (int i = 1; i < peoples.size(); i+=2) {
                //神来之笔，定义一个临时集合，存储上一步位置位偶数的元素
                People p = peoples.get(i);
                tempPeoples.add(p);
            }

            System.out.println("第"+a+"次死循环的"+"临时集合大小： "+tempPeoples.size()+" "+tempPeoples);
            //将上一步删除了位置为奇数的临时集合，给people集合，进行再一次遍历
            //反思：当时我就是不知道怎么处理，遍历集合并删除位置为奇数位的元素，这一步好做，
            // 然后我总想着怎么定义list.size的for循环或者while死循环，并且还没有想到面向对象的思想
            //并且总是认为位置就是集合的索引，混为一谈，然后每一个索引的元素记录编号，导致很难处理。面向对象就把编号和位置单独拿出来了
            peoples = tempPeoples;
            //peoples.addAll(tempPeoples);      不可以用这个，因为addall是添加，我需要的是覆盖掉用来的列表
        }

        System.out.println("----------------------------");

        //弹幕,没看懂：第一轮删除位置号除以1的商为奇数的数，第二轮除以2的商为奇数，第三轮除以4商奇。第六轮除以32商奇。最后剩下64
        People luckPeople = peoples.get(0);
        System.out.println(luckPeople);
        // 一行代码一行诗！
        /**
         * 总结，从运行结果来看：
         * 总量100的死循环，第一次循环留下来的索引为偶数位的元素有50个，第二次循环留下了25个，然后是12个，6个，3个
         * 最后是3个中的第二个为死循环最终结果，所有需要在意每一轮的第二个结果元素的位置，五轮循环分别是：4，8，16，32,64，最后一轮元素位置就是64，无需考虑
         *
         */
    }

    public static boolean isCanUse(int code){
        //遍历方式考虑过增强for，但总是考虑.size的普通for循环
        for (People people : peoples) {
            if(people.getCode() == code) {
                return false; // 重复了，不能用
            }
        }
        return true; // 此编号，没有重复，可以使用！
    }
}
